//
// Created by Administrator on 2025/8/30.
//

#include <android/log.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#include "sip_register.hpp"
#include "base_config.hpp"
#include "eXosip2/eX_register.h"
#include "osipparser2/osip_message.h"
#include "osipparser2/osip_list.h"
#include "xml_builder.hpp"
#include "sdp_parser.hpp"
#include "rtp_sender.hpp"
#include "pugixml.hpp"

#define TAG "JNI-SipRegister"
#define LGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)

void SipRegister::initialize(std::string &local_host,
                             std::string &server_host,
                             int server_port,
                             std::string &server_code,
                             std::string &server_domain,
                             std::string &device_code,
                             std::string &serial_number,
                             std::string &device_name,
                             std::string &password,
                             double longitude,
                             double latitude) {
    this->_local_host = local_host;
    this->_server_host = server_host;
    this->_server_port = server_port;
    this->_server_code = server_code;
    this->_server_domain = server_domain;
    this->_device_code = device_code;
    this->_serial_number = serial_number;
    this->_device_name = device_name;
    this->_password = password;
    this->_longitude = longitude;
    this->_latitude = latitude;

    struct eXosip_t *context = eXosip_malloc();
    if (!context) {
        LGE("Failed to allocate eXosip context");
        return;
    }

    int result = eXosip_init(context);
    if (result != 0) {
        LGE("eXosip_init failed: %d", result);
        return;
    }

    // 监听本地端口
    result = eXosip_listen_addr(context, IPPROTO_UDP, nullptr, 5060, AF_INET, 0);
    if (result != 0) {
        LGE("eXosip_listen_addr failed: %d", result);
        eXosip_quit(context);
        return;
    }

    _ex_context = context;
    if (_sip_event_thread == nullptr) {
        _running = true;
        _sip_event_thread = new std::thread(&SipRegister::sipEventLoop, this);
    }
}

void SipRegister::setSipEventCallback(JNIEnv *env, jobject callback) {
    if (!_ex_context) {
        LGE("eXosip context is not initialized");
        return;
    }

    if (_callback_obj) {
        env->DeleteGlobalRef(_callback_obj);
    }
    _callback_obj = env->NewGlobalRef(callback);
    env->GetJavaVM(&_jvm);

    // 构造 URI
    char client[256];
    snprintf(client, sizeof(client), "sip:%s@%s", _device_code.c_str(), _server_domain.c_str());
    char registrar[256];
    snprintf(registrar, sizeof(registrar), "sip:%s:%d", _server_host.c_str(), _server_port);

    if (_reg_id > 0 && _reg_state != REG_STATE_IDLE) {
        _reg_id = -1;
    }

    osip_message_t *reg = nullptr;
    int reg_id = eXosip_register_build_initial_register(_ex_context,
                                                        client,
                                                        registrar,
                                                        nullptr,
                                                        REGISTER_EXPIRED_TIME, &reg);
    if (reg_id < 0) {
        callbackToJava(4011, "构建注册请求失败");
        return;
    }
    _reg_id = reg_id;
    _reg_state = REG_STATE_SENT_INITIAL;
    _is_do_unregister = false;

    int result = eXosip_register_send_register(_ex_context, _reg_id, reg);
    if (result != 0) {
        callbackToJava(4012, "发送注册请求失败");
        _reg_state = REG_STATE_FAILED;
        return;
    }
}

void SipRegister::heartbeat() {
    while (_heartbeat_running) {
        for (int i = 0; i < HEARTBEAT_INTERVAL * 10 && _heartbeat_running; ++i) {
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }

        if (!_heartbeat_running || !_ex_context || _reg_id <= 0) {
            break;
        }

        // 构造新的 MESSAGE 请求（发给平台）
        char to_uri[256];
        snprintf(to_uri, sizeof(to_uri), "sip:%s:%d", _server_host.c_str(), _server_port);

        char from_uri[256];
        snprintf(from_uri,
                 sizeof(from_uri),
                 "sip:%s@%s", _device_code.c_str(), _server_domain.c_str());

        osip_message_t *msg = nullptr;
        int result = eXosip_message_build_request(_ex_context,
                                                  &msg,
                                                  "MESSAGE",
                                                  to_uri,
                                                  from_uri,
                                                  nullptr);
        if (result == 0) {
            osip_message_set_content_type(msg, "Application/MANSCDP+xml");
            int sn = _sn_cache.fetch_add(1);
            std::string heartbeat_xml = XmlBuilder::buildHeartbeat(std::to_string(sn),
                                                                   _device_code);
            osip_message_set_body(msg, heartbeat_xml.c_str(), heartbeat_xml.length());
            eXosip_message_send_request(_ex_context, msg);
        }
    }
}

void SipRegister::sipEventLoop() {
    int event_count = 0;
    auto last_log_time = std::chrono::steady_clock::now();
    while (_running) {
        eXosip_event_t *event = eXosip_event_wait(_ex_context, 100, 0);
        if (event == nullptr) {
            // 定期处理eXosip内部任务
            eXosip_execute(_ex_context);
            event_count++;
            auto now = std::chrono::steady_clock::now();
            auto diff = std::chrono::duration_cast<std::chrono::seconds>(now - last_log_time);
            if (diff.count() >= 10) {
                LGD("Event loop alive, processed %d cycles in last 10 seconds", event_count);
                event_count = 0;
                last_log_time = now;
            }
            continue;
        }

        auto response = event->response;
        switch (event->type) {
            case EXOSIP_REGISTRATION_SUCCESS: // 用户注册或者注销成功时触发
                registerSuccess();
                break;
            case EXOSIP_REGISTRATION_FAILURE: // 用户注册或者注销失败时触发
                registerFailed(response);
                break;
            case EXOSIP_MESSAGE_NEW: // 新的对话外请求到达时触发，比如：GB28181平台查询设备信息
                sipMessage(event);
                break;
            case EXOSIP_CALL_INVITE: // 收到新的呼叫邀请时触发，比如：GB28181平台拉流
                /**
                 * 接收平台发来的SDP协商信息
                 * 解析远程IP和端口
                 * 构造本地SDP响应
                 * 发送200 OK响应建立连接
                 * 开始推流到指定地址
                 * */
                startPushStream(event);
                break;
            case EXOSIP_CALL_NOANSWER: // 呼叫超时无应答时触发，比如：设备呼叫平台无应答
                LGD("No answer for call");
                break;
            case EXOSIP_CALL_CANCELLED: // 呼叫被取消时触发，比如：设备主动取消呼叫平台，被平台挂断就会触发
                LGD("Call cancelled");
                break;
            case EXOSIP_CALL_CLOSED : // 收到 BYE 请求，呼叫结束时触发
                /**
                 * 接收BYE请求
                 * 停止媒体推流
                 * 清理会话资源
                 * */
                callbackToJava(1001, "停止 H.264+G.711A");
                break;
            default:
                break;
        }
        eXosip_event_free(event);
    }
}

void SipRegister::registerSuccess() {
    if (_is_do_unregister) {
        callbackToJava(201, "注销成功");
        _reg_state = REG_STATE_IDLE;
        _heartbeat_running = false;
        if (_heartbeat_thread && _heartbeat_thread->joinable()) {
            _heartbeat_thread->join();
            delete _heartbeat_thread;
            _heartbeat_thread = nullptr;
        }
    } else {
        callbackToJava(200, "注册成功");
        _reg_state = REG_STATE_SUCCESS;
        if (_heartbeat_running) return;
        _heartbeat_running = true;
        _heartbeat_thread = new std::thread(&SipRegister::heartbeat, this);
    }
}

void SipRegister::registerFailed(osip_message_t *response) {
    if (_reg_state != REG_STATE_IDLE) {
        int status_code = response->status_code;
        if (status_code == 401 && _reg_state == REG_STATE_SENT_INITIAL) {
            eXosip_add_authentication_info(_ex_context,
                                           _device_name.c_str(),
                                           _device_code.c_str(),
                                           _password.c_str(),
                                           "MD5", nullptr);
            osip_message_t *auth_reg = nullptr;
            int result = eXosip_register_build_register(_ex_context,
                                                        _reg_id,
                                                        REGISTER_EXPIRED_TIME,
                                                        &auth_reg);
            if (result != 0) {
                callbackToJava(4013, "构建认证注册请求失败");
                _reg_state = REG_STATE_FAILED;
                return;
            }

            result = eXosip_register_send_register(_ex_context, _reg_id, auth_reg);
            if (result != 0) {
                callbackToJava(4014, "发送认证注册请求失败");
                _reg_state = REG_STATE_FAILED;
                return;
            }
            _reg_state = REG_STATE_SENT_AUTH;
        } else {
            callbackToJava(status_code, "未知错误");
            _reg_state = REG_STATE_FAILED;
        }
    }
}

void SipRegister::sipMessage(eXosip_event_t *event) {
    if (event->request == nullptr) return;

    // 打印请求详情
    auto from = event->request->from->url;
    auto to = event->request->to->url;
    LGD("Message from: %s@%s, to: %s@%s",
        from->username ? from->username : "Unknown", from->host ? from->host : "Unknown",
        to->username ? to->username : "Unknown", to->host ? to->host : "Unknown");

    // 先回复 200 OK
    osip_message_t *ack = nullptr;
    if (eXosip_message_build_answer(_ex_context, event->tid, 200, &ack) == 0) {
        eXosip_message_send_answer(_ex_context, event->tid, 200, ack);
    }

    // 解析 Content-Type
    osip_content_type_t *ct = osip_message_get_content_type(event->request);
    if (!ct || osip_strcasecmp(ct->type, "Application") != 0 ||
        osip_strcasecmp(ct->subtype, "MANSCDP+xml") != 0) {
        LGE("Unsupported content type");
        return;
    }

    // 获取请求体
    auto *body_ptr = (osip_body_t *) osip_list_get(&event->request->bodies, 0);
    if (!body_ptr || !body_ptr->body) return;

    std::string content(body_ptr->body, body_ptr->length);
    LGD("%s", content.c_str());

    pugi::xml_document xml;
    pugi::xml_parse_result xml_result = xml.load_string(content.c_str());
    if (!xml_result) {
        LGE("XML parsed with errors");
        return;
    }

    pugi::xml_node query_node = xml.child("Query");
    if (!query_node) {
        LGE("No Query node found in XML");
        return;
    }

    std::string cmd_type = query_node.child("CmdType").text().get();
    std::string sn = query_node.child("SN").text().get();

    std::string response_xml;
    if (cmd_type == "Catalog") {
        response_xml = XmlBuilder::buildCatalog(sn,
                                                _device_code,
                                                _server_domain,
                                                _longitude,
                                                _latitude);
    } else if (cmd_type == "DeviceInfo") {
        response_xml = XmlBuilder::buildDeviceInfo(sn,
                                                   _device_code,
                                                   _device_name,
                                                   _serial_number);
    } else {
        LGE("Unsupported CmdType: %s", cmd_type.c_str());
        return;
    }

    // 构造新的 MESSAGE 请求（发给平台）
    char to_uri[256];
    snprintf(to_uri, sizeof(to_uri), "sip:%s:%d", _server_host.c_str(), _server_port);

    char from_uri[256];
    snprintf(from_uri, sizeof(from_uri), "sip:%s@%s",
             _device_code.c_str(),
             _server_domain.c_str());

    osip_message_t *msg = nullptr;
    int result = eXosip_message_build_request(_ex_context,
                                              &msg,
                                              "MESSAGE",
                                              to_uri,
                                              from_uri,
                                              nullptr);
    if (result == 0) {
        osip_message_set_content_type(msg, "Application/MANSCDP+xml");
        osip_message_set_body(msg, response_xml.c_str(), response_xml.length());
        eXosip_message_send_request(_ex_context, msg);
    }
}

void SipRegister::startPushStream(eXosip_event_t *event) {
    if (event->request == nullptr) return;

    // 打印请求详情
    auto from = event->request->from->url;
    auto to = event->request->to->url;
    LGD("Message from: %s@%s, to: %s@%s",
        from->username ? from->username : "Unknown", from->host ? from->host : "Unknown",
        to->username ? to->username : "Unknown", to->host ? to->host : "Unknown");

    auto *body_ptr = (osip_body_t *) osip_list_get(&event->request->bodies, 0);
    if (!body_ptr || !body_ptr->body) {
        LGE("INVITE body is empty");
        eXosip_call_send_answer(_ex_context, event->tid, 488, nullptr);
        return;
    }
    std::string sdp(body_ptr->body, body_ptr->length);
    LGD("%s", sdp.c_str());

    SdpStruct sdp_struct = SdpParser::parse(sdp);
    if (sdp_struct.remote_port == 0 || sdp_struct.remote_ip.empty()) {
        LGD("Failed to parse SDP IP/Port");
        eXosip_call_send_answer(_ex_context, event->tid, 488, nullptr);
        return;
    }

    // 初始化 RTP Socket
    if (!RtpSender::getSender()->initRtpSocket(sdp_struct)) {
        LGE("Failed to initialize RTP socket after sending 200 OK");
        return;
    }

    LGD("Platform wants stream: %s:%d, SSRC: %s, Local port: %d",
        sdp_struct.remote_ip.c_str(), sdp_struct.remote_port, sdp_struct.ssrc.c_str(),
        sdp_struct.local_port);

    // 构建 200 OK 响应
    osip_message_t *answer = nullptr;
    int ret = eXosip_call_build_answer(_ex_context, event->tid, 200, &answer);
    if (ret != 0 || !answer) {
        LGD("Failed to build 200 OK answer (ret=%d)", ret);
        eXosip_call_send_answer(_ex_context, event->tid, 500, nullptr);
        return;
    }

    std::string sdp_answer = SdpParser::buildSdpAnswer(_device_code, _local_rtp_ip,
                                                       sdp_struct.local_port, sdp_struct.ssrc);
    if (sdp_answer.empty()) {
        osip_message_free(answer);
        eXosip_call_send_answer(_ex_context, event->tid, 500, nullptr);
        return;
    }

    // 设置 SDP body 和 Content-Type
    osip_message_set_body(answer, sdp_answer.c_str(), sdp_answer.length());
    osip_message_set_content_type(answer, "application/sdp");
    ret = eXosip_call_send_answer(_ex_context, event->tid, 200, answer);
    if (ret != 0) {
        callbackToJava(402, "初始化推流失败");
        return;
    }

    callbackToJava(1000, "开始 H.264+G.711A");
}

void SipRegister::callbackToJava(int code, const std::string &content) {
    if (!_callback_obj || !_jvm) return;

    JNIEnv *env;
    bool needDetach = false;

    int status = _jvm->GetEnv((void **) &env, JNI_VERSION_1_6);
    if (status == JNI_EDETACHED) {
        status = _jvm->AttachCurrentThread(&env, nullptr);
        needDetach = true;
    }

    if (status != JNI_OK) return;

    jclass cls = env->GetObjectClass(_callback_obj);
    jmethodID mid = env->GetMethodID(cls, "onEventReceived", "(ILjava/lang/String;)V");

    if (mid) {
        jstring j_message = env->NewStringUTF(content.c_str());
        env->CallVoidMethod(_callback_obj, mid, code, j_message);
        env->DeleteLocalRef(j_message);
    }

    if (needDetach) {
        _jvm->DetachCurrentThread();
    }
}

void SipRegister::unregister() {
    if ((_reg_id <= 0 && _reg_state == REG_STATE_IDLE) || !_ex_context || !_running) {
        return;
    }

    int current_reg_id = _reg_id;
    _is_do_unregister = true;

    // 构建注销请求(Expires设置为0)
    osip_message_t *unreg = nullptr;
    int result = eXosip_register_build_register(_ex_context,
                                                current_reg_id,
                                                0,
                                                &unreg);
    if (result != 0) {
        LGD("eXosip_register_build_register for unregistration failed: %d", result);
        return;
    }

    // 发送注销请求
    result = eXosip_register_send_register(_ex_context, current_reg_id, unreg);
    if (result != 0) {
        LGD("eXosip_register_send_register for unregistration failed: %d", result);
        return;
    }

    _reg_id = -1;
    _reg_state = REG_STATE_IDLE;
}

SipRegister::~SipRegister() {
    _running = false;

    if (_sip_event_thread && _sip_event_thread->joinable()) {
        _sip_event_thread->join();
        delete _sip_event_thread;
        _sip_event_thread = nullptr;
    }

    _heartbeat_running = false;
    if (_heartbeat_thread && _heartbeat_thread->joinable()) {
        _heartbeat_thread->join();
        delete _heartbeat_thread;
        _heartbeat_thread = nullptr;
    }

    if (_callback_obj && _jvm) {
        JNIEnv *env;
        int status = _jvm->GetEnv((void **) &env, JNI_VERSION_1_6);
        if (status == JNI_OK && env) {
            env->DeleteGlobalRef(_callback_obj);
        }
    }

    if (_ex_context) {
        eXosip_quit(_ex_context);
        _ex_context = nullptr;
    }

    LGD("SipRegister destroyed");
}